#include<iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include<unistd.h>
#include<string.h>
#include <netinet/in.h>//bind
#include <arpa/inet.h>//bind
using namespace std;

const uint16_t default_port = 8080;
class UdpServer
{
public:
    UdpServer(uint16_t port = default_port) 
    :_sockfd(-1)
    , _port(port)
    , _ip()
    {}

    bool InitServer()
    {
        //1. 创建套接字
        _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if(_sockfd < 0){
            cerr<< "socket error" << endl;
            return false;//创建失败
        }

        //cout<<"socket create success, sockfd: "<<_sockfd<<endl;

        //2. 给该套接字绑定IP和端口
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;//协议种类
        local.sin_port = htons(_port); //转换端口号为网络序列
        // 云服务器，不允许用户直接bind公网IP，另外, 实际正常编写的时候，我们也不会指明IP
        // local.sin_addr.s_addr = inet_addr("42.192.83.143"); //点分十进制，字符串风格[0-255].[0-255].[0-255].[0-255]
        local.sin_addr.s_addr = INADDR_ANY;//`INADDR_ANY`就是不关心是数据是从哪个IP来的，只要是发给我的这个端口，就全部接收
        
        if(bind(_sockfd, (struct sockaddr*)&local, sizeof(local)) < 0){
            //绑定失败
            cerr << "bind error" <<endl;
            return false;
        }
        //cout << "bind success!" << endl;

        return true;
    }
    void Start()
    {
        #define NUM 1024
        char buffer[NUM] = {0};
        while(true)
        {
            struct sockaddr_in peer;//用来保存客户端的信息（ip..），方便后续发回消息
            socklen_t len = sizeof(peer);
            ssize_t s = recvfrom(_sockfd, buffer, sizeof(buffer)-1, 0, (struct sockaddr*)&peer, &len);
            if(s >= 0){
                buffer[s] = '\0';
                FILE* fp = popen(buffer, "r");

                int port = ntohs(peer.sin_port);
                string ip = inet_ntoa(peer.sin_addr); //直接传addr_in结构体，会将里面保存的整数IP转化成字符串IP
                cout << ip << ":" << port << "#" << buffer <<endl;

                string echo;
                char line[1024];
                while( fgets(line, sizeof(line), fp) != nullptr)
                {
                    echo += line;
                }
                pclose(fp);
                sendto(_sockfd, echo.c_str(), echo.size(), 0,(struct sockaddr*)&peer, len);

            }
            else{
                cerr<<"recvfrom error"<<endl;
            }
        }
    }
    ~UdpServer()
    {
        if(_sockfd >= 0)
        {
            close(_sockfd);
        }
    }
private:
    int _sockfd; //套接字对应的文件描述符
    string _ip;//IP地址
    uint16_t _port;//端口号
};


int main()
{
    UdpServer* my_server = new UdpServer();
    my_server->InitServer();
    my_server->Start();
    return 0;
}